/**
 * threejs 场景对象的数据结构是一颗树，与 DOM 树类似，
 * 我们可以针对树状结构进行查询、遍历等操作
 */
import * as THREE from '../../build/three.module.js';
import {
  OrbitControls
} from '../../jsm/controls/OrbitControls.js';

// 通过一个简单的机器人模型树来演示树状结构模型
const scene = new THREE.Scene();

/**
 * 创建球体网格模型对象
 * @param {string} name 模型名称
 * @param {number} R 球体半径
 * @param {number} x 初始化位置 x 坐标
 * @param {number} y 初始化位置 y 坐标
 * @param {number} z 初始化位置 z 坐标
 */
const sphereMesh = (name, R, x, y, z) => {
  let geometry = new THREE.SphereGeometry(R, 25, 25); // 球体几何
  let material = new THREE.MeshPhongMaterial({
    color: 0x0000ff
  }); // 材质对象
  let mesh = new THREE.Mesh(geometry, material); // 网格模型
  mesh.position.set(x, y, z);
  mesh.name = name;
  return mesh;
}

/**
 * 创建圆柱体模型
 * @param {string} name 模型名称
 * @param {number} R 圆柱体半径
 * @param {number} h 圆柱体高度
 * @param {number} x 初始化位置 x 坐标
 * @param {number} y 初始化位置 y 坐标
 * @param {number} z 初始化位置 z 坐标
 */
const cylinderMesh = (name, R, h, x, y, z) => {
  let geometry = new THREE.CylinderGeometry(R, R, h, 25, 25);
  let material = new THREE.MeshPhongMaterial({
    color: 0x0000ff
  });
  let mesh = new THREE.Mesh(geometry, material);
  mesh.position.set(x, y, z);
  mesh.name = name;
  return mesh;
}

/**
 * 头部网格模型和组
 */
let haedMesh = sphereMesh('脑壳', 10, 0, 0, 0);
let leftEyeMesh = sphereMesh('左眼', 1, 8, 5, 4);
let rightEyeMesh = sphereMesh('右眼', 1, 8, 5, -4);
let headGroup = new THREE.Group();
headGroup.name = '头部';
headGroup.add(haedMesh, leftEyeMesh, rightEyeMesh);

/**
 * 身体网格模型
 */
let neckMesh = cylinderMesh('脖子', 3, 10, 0, -15, 0);
let bodyMesh = cylinderMesh('腹部', 14, 30, 0, -35, 0);
let leftLegMesh = cylinderMesh('左腿', 4, 60, 0, -80, -7);
let rightLegMesh = cylinderMesh('右腿', 4, 60, 0, -80, 7);
let legGroup = new THREE.Group();
legGroup.name = '腿';
legGroup.add(leftLegMesh, rightLegMesh);
let bodyGroup = new THREE.Group();
bodyGroup.name = '身体';
bodyGroup.add(neckMesh, bodyMesh, legGroup);

/**
 * 人Group
 */
let personGroup = new THREE.Group();
personGroup.name = '人';
personGroup.add(headGroup, bodyGroup);
personGroup.translateY(50);
scene.add(personGroup);

// 光源
const directionalL = new THREE.DirectionalLight(0xffffff, 1);
directionalL.position.set(300, 200, 200);
directionalL.target = personGroup;
scene.add(directionalL);

// 辅助线
const axceH = new THREE.AxesHelper(200);
scene.add(axceH);

// 相机
const k = innerWidth / innerHeight,
      s = 200,
      camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
camera.position.set(400, 400, 400);
camera.lookAt(scene.position);

// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
renderer.setClearColor(0xaaaaaa);
document.body.appendChild(renderer.domElement);

new OrbitControls(camera, renderer.domElement);

function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}
render();

// 三秒后遍历处理
setTimeout(() => {
  // 通过 traverse 方法遍历 scene 对象及其子元素
  scene.traverse((obj) => {
    if (obj.type === 'Group') {
      console.log(obj.name);
    }
    if (obj.type === 'Mesh') {
      console.log(` ${obj.name}`);
      obj.material.color.set(0xffff00);
    }
    if (obj.name === '左眼' || obj.name === '右眼') {
      obj.material.color.set(0x000000);
    }
    // 打印 id 属性
    console.log(obj.id);
    // 打印该对象的父对象
    console.log(obj.parent);
    // 打印该对象的子对象
    console.log(obj.children);
  })
}, 3000);

setTimeout(() => {
  // 继承自 Object3D 的实例，都拥有 getOobjectById、getObjectByName 方法，通过 id 和 name 查询树状结构里的某个模型
  let idNode = scene.getObjectById(4);
  console.log(idNode);
  let nameNode = scene.getObjectByName('左腿');
  console.log(nameNode);
}, 4000);